package cn.yx.common.web.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.yx.common.core.constant.SeparatorConstant;
import cn.yx.common.core.enums.ContentTypeEnum;
import cn.yx.common.core.exception.CommonException;
import cn.yx.common.core.pojo.ResponseVo;
import cn.yx.common.core.util.json.jackson.JsonUtil;
import cn.yx.common.web.constant.message.WebUtilMessageKey;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Arrays;
import java.util.Objects;

/**
 * <p>Web工具类</p>
 *
 * @author Wgssmart
 */
@Slf4j
public final class WebUtil {

    private WebUtil() {
    }

    /**
     * 获取网站根路径
     *
     * @param request HttpServletRequest对象
     * @return 网站根路径
     */
    public static String getRootPath(HttpServletRequest request) {
        return request.getServletContext().getRealPath("/");
    }

    /**
     * 在网站根路径下创建目录，可以是多级目录
     *
     * @param request HttpServletRequest对象
     * @param dirs    在网站根目录下要创建的目录，如static/uploads
     * @return 创建的目录的绝对路径
     */
    public static String mkdirsInRootPath(HttpServletRequest request, String dirs) {
        return FileUtil.mkdir(new File(getRootPath(request), dirs)).getAbsolutePath();
    }

    /**
     * 获取HTTP请求URL的最后/部分的内容
     *
     * @param request HttpServletRequest对象
     * @return 请求URL中最后/部分的内容
     */
    public static String getReqMethod(HttpServletRequest request) {
        String uri = request.getRequestURI();
        return uri.substring(uri.lastIndexOf(SeparatorConstant.SLASH) + 1);
    }

    /**
     * 从request中获取JSON请求数据转化成Java对象
     *
     * @param request
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T> T getRequestData(HttpServletRequest request, Class<T> tClass) {
        try (ServletInputStream servletInputStream = request.getInputStream()) {
            return cn.yx.common.core.util.io.IoUtil.objectFromJsonInput(servletInputStream, tClass);
        } catch (IOException e) {
            log.error("get request data error: {}", e.getMessage());
            throw new CommonException(WebUtilMessageKey.GET_REQUEST_DATA_ERROR, e);
        }
    }

    /**
     * 把指定的输入流通过response对象的输出流输出
     *
     * @param in  输入流
     * @param out 输出流
     */
    public static void outResponse(InputStream in, OutputStream out) {
        try {
            IoUtil.write(out, false, in.readAllBytes());
        } catch (IOException e) {
            log.error("out response error: {}", e.getMessage());
            throw new CommonException(WebUtilMessageKey.OUT_RESPONSE_ERROR, e);
        }
    }

    /**
     * 把指定的输入流通过response对象的输出流输出
     *
     * @param in              输入流
     * @param response        HttpServletResponse响应对象
     * @param contentTypeEnum 响应对象的内容类型枚举
     */
    public static void outResponse(InputStream in, HttpServletResponse response, ContentTypeEnum contentTypeEnum) {
        response.setContentType(contentTypeEnum.getValue());
        try {
            outResponse(in, response.getOutputStream());
        } catch (IOException e) {
            log.error("out response error: {}, content type: {}", e.getMessage(), contentTypeEnum.getValue());
            throw new CommonException(WebUtilMessageKey.GET_OUTPUT_STREAM_ERROR, e);
        }
    }

    /**
     * 把字符串内容通过指定的内容类型通过response对象输出流输出
     *
     * @param response        HttpServletResponse响应对象
     * @param content         字符串内容
     * @param contentTypeEnum 响应对象的内容类型枚举
     */
    public static void outResponse(HttpServletResponse response, String content, ContentTypeEnum contentTypeEnum) {
        response.setContentType(contentTypeEnum.getValue());
        try {
            PrintWriter printWriter = response.getWriter();
            printWriter.write(content);
        } catch (IOException e) {
            log.error("out response error: {}, content type: {}", e.getMessage(), contentTypeEnum.getValue());
            throw new CommonException(WebUtilMessageKey.GET_WRITER_ERROR, e);
        }
    }

    /**
     * 写出ResponseStatusVO
     *
     * @param response   HttpServletResponse响应对象
     * @param responseVo ResponseVo
     * @throws IOException
     */
    public static void outResponseVo(HttpServletResponse response, ResponseVo<?> responseVo) {
        outResponse(response, JsonUtil.toJsonStr(responseVo), ContentTypeEnum.JSON);
    }

    /**
     * 写出cookie
     *
     * @param response
     * @param name
     * @param value
     */
    public static void setCookie(HttpServletResponse response, String name, String value) {
        Cookie cookie = new Cookie(name, value);
        response.addCookie(cookie);
    }

    /**
     * 写出cookie
     *
     * @param response
     * @param name
     * @param value
     * @param expiration 失效时间，单位为s
     */
    public static void setCookie(HttpServletResponse response, String name, String value, int expiration) {
        Cookie cookie = new Cookie(name, value);
        cookie.setMaxAge(expiration);
        response.addCookie(cookie);
    }

    /**
     * 根据cookie名称获取Cookie对象
     *
     * @param request
     * @param name
     * @return
     */
    public static Cookie getCookie(HttpServletRequest request, String name) {
        Cookie[] cookies = request.getCookies();
        if (ArrayUtil.isEmpty(cookies)) {
            return null;
        }
        return Arrays.stream(cookies).filter(c -> name.equals(c.getName())).findFirst().orElse(null);
    }

    /**
     * 根据cookie名称获取cookie值
     *
     * @param request
     * @param name
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String name) {
        Cookie cookie = getCookie(request, name);
        return Objects.nonNull(cookie) ? cookie.getValue() : null;
    }

    /**
     * 移除指定名称的Cookie
     *
     * @param response
     * @param name
     */
    public static void removeCookie(HttpServletResponse response, String name) {
        setCookie(response, name, "", 0);
    }

}
